/**
 * 判断是否是对象
 * @param {*} data 
 * @returns 
 */
export function isObject(data) {
  return typeof data !== "object" && data !== null;
}

/**
 * 增加一个属性
 * @param {*} data 
 * @param {*} key 
 * @param {*} value 
 */
export function def(data, key, value) {
  Object.defineProperty(data, key, {
    enumerable: false,
    configurable: false,
    value
  })
}

/**
 * 通过代理在vm._data上取值
 * @param {*} vm 
 * @param {*} source 
 * @param {*} key 
 */
export function proxy(vm, source, key) {
  Object.defineProperty(vm, key, {
    get() {
      return vm[source][key];
    },
    set(newValue) {
      vm[source][key] = newValue;
    }
  })
}

const LIFECYCLE_HOOKS = [
  "beforeCreate",
  "created",
  "beforeMount",
  "mounted",
  "beforeUpdate",
  "updated",
  "activated",
  "deactivated",
  "beforeDestory",
  "destroyed",
  "errorCaptures"
]

let strats = {};

function mergeHook(parentVal, childVal) {
  if (childVal) {
    // 如果 孩子有值
    if (parentVal) {
      // 如果父亲有值， 就直接拼接
      return parentVal.concat(childVal);
    } else {
      // 如果孩子有值而父亲没有值，就将孩子包装成数组
      return [childVal]; // Vue.options.beforeCreate = [childVal]
    }
  } else {
    return parentVal; // 直接返回父亲， 因为没有孩子
  }
}

LIFECYCLE_HOOKS.forEach(hook => {
  strats[hook] = mergeHook;
})

export function mergeOptions(parent, child) {
  const options = {};
  for (let key in parent) {
    mergeField(key);
  }

  for (let key in child) {
    // 如果已经合并过了就不需要再合并了
    if (!parent.hasOwnProperty(key)) {
      mergeField(key);
    }
  }

  function mergeField(key) {
    // 两个组件间， data是函数
    // 忌讳if else if else
    // 策略模式， 根据不同的属性， 调用不同的策略
    if (strats[key]) {
      // 这里就是包含了mergeHook的逻辑
      options[key] = strats[key](parent[key], child[key])
    } else if (!isObject(parent[key]) && !isObject(child[key])) {
      options[key] = Object.assign(parent[key], child[key]);
    } else {
      if (child[key] == null) {
        options[key] = parent[key]
      } else {
        options[key] = child[key]; // 用儿子的值，直接覆盖掉，父亲的道
      }
    }
  }
  // {data: {}}  {data: {}}

  return options;
}